
module EG(
  input  wire        clk,
  input  wire        rst_n,
  input  wire        clken,
  input  wire [ 4:0] slot,
  input  wire [ 1:0] stage,
  input  wire        rhythm,
  input  wire        am,
  input  wire [ 6:0] tl,
  input  wire [ 3:0] ar,
  input  wire [ 3:0] dr,
  input  wire [ 3:0] sl,
  input  wire [ 3:0] rr,
  input  wire [ 3:0] rks,
  input  wire        key,

  output reg  [ 6:0] egout
);

reg        memwr;
reg [24:0] memin;
reg [ 4:0] rslot;
wire[24:0] memout;

EnvelopeMemory U_EnvelopeMemory(
    .clk   (clk),
    .rst_n (rst_n),
    .waddr (slot),
    .wr    (memwr),
    .wdata (memin),
    .raddr (rslot),
    .rdata (memout)
);

reg  [6:0] aridx;
wire [6:0] ardata;

AttackTable U_AttackTable(
    .clk   ( clk    ),
    .rst_n ( rst_n  ),
    .addr  ( aridx  ),
    .data  ( ardata )
);

reg[17:0] lastkey;
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
	lastkey <= #1 18'b0;
    else if(!clken)
	lastkey <= #1 lastkey;
    else if(stage==2'd2)
	lastkey <= #1 key;
end

reg[17:0] ntable;
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
	ntable <= #1 18'h3FFFF;
    else if(!clken)
	ntable <= #1 ntable;
    else 
	ntable <= #1 {ntable[16:0], (ntable[17]^ntable[14])};
end

reg[19:0] amphase;
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
	amphase <= #1 20'h08000;
    else if(!clken)
	amphase <= #1 amphase;
    else if(amphase[19:15]==5'h1f)
	amphase <= #1 {5'h01, amphase[14:0]+1'b1};
    else
	amphase <= #1 amphase + 1'b1;
end

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
	memwr <= #1 1'b0;
    else if(clken)
	memwr <= #1 memwr;
    else if(stage==2'd2)
	memwr <= #1 1'b1;
    else
	memwr <= #1 1'b0;
end


parameter Attack = 2'b01;
parameter Decay  = 2'b10;
parameter Release= 2'b11;
parameter Finish = 2'b00;

reg[ 1:0] eg_next_state;
reg[ 1:0] eg_curr_state;
reg[22:0] egphase;
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
	eg_curr_state <= #1 Finish;
    else if(!clken)
	eg_curr_state <= #1 eg_curr_state;
    else
        eg_curr_state <= #1 eg_next_state;
end

always @(*)begin
    if(stage==2'b00)
	eg_next_state = memout[24:23];
    else if(stage==2'd2)begin
	if((!lastkey[slot]) && key)
		eg_next_state = Attack;
	else if(lastkey[slot] && (!key) && (eg_curr_state!=Finish))
		eg_next_state = Release;
	else
	    case(eg_curr_state)
            Attack: 
		if(egphase[22])
		    eg_next_state = Decay;
	        else
	            eg_next_state = Attack;
	    Decay:
		if(egphase[22:18] >= {1'b0, sl})
		    eg_next_state = Release;
	        else
		    eg_next_state = Decay;
	    Release: 
		 if(egphase[22:18]>=5'hf)  
	            eg_next_state = Finish;
                 else
	            eg_next_state = Release;		
	    Finish: eg_next_state = Finish; 
        endcase
    end	
end

reg  [22:0] dphase;
wire [22:0] egphase_tmp = egphase - dphase[22:0];

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
	egphase <= #1 23'b0;
    else if(stage == 2'd0)
	egphase <= #1 memout[22:0];
    else if(stage == 2'd2)begin
        if((!lastkey[slot]) && key)
            egphase <= #1 23'h3FFFFF;
        else
            case(eg_curr_state)
            Attack:
		if(egphase_tmp[22])
	            egphase <= #1 23'b0;
	        else
		    egphase <= #1 egphase_tmp;
            Decay,Release:
	        egphase <= #1 egphase + dphase[22:0];
            Finish: 
	        egphase <= #1 23'h7FFFFF;	    
            endcase		    
    end
end

wire[5:0] rks_tmp = 3'b110 * {1'b1, rks[1:0]};
reg [4:0] rm;
always @(*)begin
    if(stage==2'd2)
	if(eg_curr_state==Attack)
	    dphase = {18'b0, rks_tmp} << rm[3:0];
        else if((eg_curr_state==Decay) || (eg_curr_state==Release))
            dphase = {20'b0, 1'b1, rks[1:0]}<<(rm[3:0]-1'b1);
        else
	    dphase = 23'b0;
    else
	    dphase = 23'b0;
end

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
	aridx <= #1 7'b0;
    else if(stage == 2'd0)
	aridx <= #1 egphase[21:15];
end

reg[4:0] rmtmp;
always @(*)begin
    if(stage == 2'd2)
        case(eg_curr_state)
	Attack: rmtmp = {1'b0, ar};
        Decay:  rmtmp = {1'b0, dr};
        Release:rmtmp = {1'b0, rr};
        default:rmtmp = 5'b0;	
        endcase		
     else
	 rmtmp = 5'b0;
end

wire[4:0] rmtmp2 = rmtmp + rks[3:2];
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
	rm <= #1 5'b0;
    else if(stage == 2'd2)
	if(rm != 5'd0)
            if(rmtmp2[4])
		rm <= #1 5'h1f;
	    else
	        rm <= #1 rmtmp2;
	else
	    rm <= #1 rmtmp;
end


reg[8:0] egtmp;
reg[8:0] egtmp2;
reg[8:0] egtmp3;
always @(*)begin
    case(eg_curr_state)
    Attack: egtmp2 = {2'b00, tl} + {2'b00, ardata};
    Decay:  egtmp2 = {2'b00, tl} + {2'b00, egphase[21:15]};
    Release:egtmp2 = {2'b00, tl} + {2'b00, egphase[21:15]};
    Finish: egtmp2 = {2'b00, 7'h7F};
    endcase	    
end

always @(*)begin
    if(ntable[0] && (slot[4:1]==4'd7) && rhythm)
	    egtmp3 = egtmp2 + 9'b010000000;
    else
	    egtmp3 = egtmp2;
end

always @(*)begin
    if(am)
	if(!amphase[19])
		egtmp = egtmp3 + {5'b0, amphase[18:14]-1'b1};
	else
		egtmp = egtmp3 + {5'b0, 4'hf-amphase[18:14]};
    else
         egtmp = egtmp3;	    
end

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
	    egout <= #1 7'b0;
    else if(stage == 2'd2)
	    if(egtmp[8:7]==2'b00)
		    egout <= #1 egtmp[6:0];
	    else
		    egout <= #1 7'h7F;
    else
        egout <= #1 egout;	    
end

reg[4:0] rslot_buf;
always @(*)begin
    if(slot == 5'd17)
	    rslot_buf = 5'd0;
    else
	    rslot_buf = slot + 1'b1;
end

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
	    rslot <= #1 5'b0;
    else if(clken)
	    rslot <= #1 rslot;
    else if(stage == 2'd2)
	    rslot <= #1 rslot_buf;
end


endmodule

